package de.zainodis.commons.xml;

import java.util.Map;

import org.xmlpull.v1.XmlPullParser;

import de.zainodis.commons.LogCat;
import de.zainodis.commons.utils.XmlUtils;

public abstract class BaseParser<T> implements IParser<T> {

   private static final String TAG = "BaseParser<T>";

   private boolean isDone = false;

   @Override
   public T parse(XmlPullParser parser) throws ParseException {

	 try {
	    int eventType = parser.getEventType();
	    while (eventType != XmlPullParser.END_DOCUMENT && !isDone) {
		  switch (eventType) {
		  case XmlPullParser.START_TAG:
			onStartTag(parser);
			break;
		  case XmlPullParser.END_TAG:
			isDone = onEndTag(parser);
			break;
		  }
		  eventType = next(isDone, parser);
	    }
	 } catch (Exception e) {
	    LogCat.e(TAG, "Parsing xml failed.", e);
	    throw new ParseException(e);
	 }
	 return getResult();
   }

   protected Map<String, String> parseAttributes(XmlPullParser parser) {
	 return XmlUtils.parseAttributes(parser);
   }

   @Override
   public int next(boolean isDone, XmlPullParser parser) throws ParseException {
	 if (isDone)
	    return -1;
	 try {
	    return parser.next();
	 } catch (Exception e) {
	    throw new ParseException("Failed to advance parser.", e);
	 }
   }

   /**
    * Required to return a result at the end of the parsing process.
    * 
    * @return the result of the parsing process which is of the type that has
    *         been specified by the implementing parser.
    */
   protected abstract T getResult();

   /**
    * Parses a start tag using the given parser.
    */
   protected abstract void onStartTag(XmlPullParser parser);

   /**
    * Parses an end tag using the given parser.
    * 
    * @return true if parsing has been completed (i.e. is done); false
    *         otherwise.
    */
   protected abstract boolean onEndTag(XmlPullParser parser);

}
